/**
 * bsw_auto_lock.h
 * 显式链接 pthread 库
 * 
 * 竹影半墙
 * 2023.10
 */
#ifndef BSW_AUTO_LOCK_H
#define BSW_AUTO_LOCK_H

#include <time.h>
#include <pthread.h>
#include "bsw_auto_compiler.h"

/**
 * 读写锁
 */
typedef pthread_rwlock_t bsw_lock_rw_t;
#define bsw_lock_rw_initializer \
    (bsw_lock_rw_t)PTHREAD_RWLOCK_INITIALIZER
#define bsw_lock_rw_init(lock)  \
    ({ lock = bsw_lock_rw_initializer; })

static bsw_always_inline int 
bsw_lock_rw_rd(bsw_lock_rw_t *lock)
{
    return pthread_rwlock_rdlock(lock);
}

static bsw_always_inline int 
bsw_lock_rw_wr(bsw_lock_rw_t *lock)
{
    return pthread_rwlock_wrlock(lock);
}

static bsw_always_inline int 
bsw_lock_rw_un(bsw_lock_rw_t *lock)
{
    return pthread_rwlock_unlock(lock);
}

/**
 * 互斥锁
 */
typedef pthread_mutex_t bsw_lock_mtx_t;
#define bsw_lock_mtx_initializer    \
    (bsw_lock_mtx_t)PTHREAD_MUTEX_INITIALIZER
#define bsw_lock_mtx_init(lock)     \
    ({ lock = bsw_lock_mtx_initializer; })

static bsw_always_inline int 
bsw_lock_mtx_lc(bsw_lock_mtx_t *lock)
{
    return pthread_mutex_lock(lock);
}

static bsw_always_inline int 
bsw_lock_mtx_un(bsw_lock_mtx_t *lock)
{
    return bsw_lock_mtx_un(lock);
}

/**
 * 条件变量
 */
typedef pthread_cond_t  bsw_cond_t;
typedef struct timespec bsw_timespec_s;

#define bsw_cond_initializer                \
    (bsw_cond_t)PTHREAD_COND_INITIALIZER
#define bsw_cond_init_monotonic(c)          \
    do {                                    \
        c = bsw_cond_initializer;           \
        (c).__data.__nwaiters = 1;          \
    } while (0)

static bsw_always_inline int 
bsw_cond_wait(bsw_cond_t *cond, bsw_lock_mtx_t *lock)
{
    return pthread_cond_wait(cond, lock);
}

static bsw_always_inline int 
bsw_cond_timedwait(bsw_cond_t *cond,
    bsw_lock_mtx_t *lock, bsw_timespec_s *ts)
{
    return pthread_cond_timedwait(cond, lock, ts);
}

static bsw_always_inline int 
bsw_cond_broadcast(bsw_cond_t *cond)
{
    return pthread_cond_broadcast(cond);
}

static bsw_always_inline int 
bsw_cond_signal(bsw_cond_t *cond)
{
    return pthread_cond_signal(cond);
}

#endif